package main

import (
	"context"
	"os"
	"os/signal"
	"runtime"
	"server/components/logger"
	"server/components/repository"
	"server/components/server"
	"slices"
	"syscall"

	_ "github.com/jackc/pgx/v5"
	_ "github.com/jackc/pgx/v5/stdlib"
	"github.com/urfave/cli/v2"
)

func runApp(ctx context.Context, args []string) {
	logger.Init(os.Getenv("SERVER_DEBUG") == "true" || slices.Index(args, "--debug") >= 0)
	// Инициализация CLI App
	var (
		pgURL   string
		port    int
		cleanDB bool
		debug   bool
	)
	app := &cli.App{
		Name: "server",
		Flags: []cli.Flag{
			&cli.BoolFlag{
				Name:        "debug",
				Usage:       "Enable debug output",
				Destination: &debug,
			},
			&cli.StringFlag{
				Name:        "pg",
				Usage:       "PostgreSQL connection URL",
				EnvVars:     []string{"SERVER_PG_URL"}, // для инициализации можно использовать переменную окружения
				DefaultText: repository.DefaultPGUrl,
				Destination: &pgURL,
				Value:       repository.DefaultPGUrl,
			},
			&cli.IntFlag{
				Name:        "port",
				Usage:       "Defines port to run server",
				EnvVars:     []string{"SERVER_PORT"},
				Destination: &port,
				DefaultText: "8088",
				Value:       8088,
			},
			&cli.BoolFlag{
				Name:        "clean",
				Usage:       "Clean DB before on start",
				EnvVars:     []string{"SERVER_CLEAN_DB"},
				Destination: &cleanDB,
			},
		},
		Action: func(cliCtx *cli.Context) error {
			ctx := cliCtx.Context
			server := server.NewServer(
				server.WithPGUrl(pgURL),
				server.WithPort(port),
				server.WithCleanDB(cleanDB))
			return server.Run(ctx)
		},
	}
	if err := app.RunContext(ctx, args); err != nil {
		logger.Logger().Fatalf("Execution failed with err %v", err)
	}
}

func main() {
	// обработка ctrl-c/ctrl-break и других прерываний
	interrupt := make(chan os.Signal)
	if runtime.GOOS == "windows" {
		signal.Notify(interrupt, os.Interrupt)
	} else {
		signal.Notify(interrupt, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
	}
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	go func() {
		for sig := range interrupt {
			logger.Logger().Debugf("Interrupted by signal '%v'", sig.String())
			cancel()
		}
	}()
	runApp(ctx, os.Args)
}
